/*
 * Trieda, pouzivana na citanie vstupu, predava DTD na dalsie spracovanie. Vytvori
 * novy XML subor obsahujuci upravene XML - zmenena hlavicka XML suboru, vytvori 
 * novy XSD subor vedla daneho XML
 */
package dtd.to.xmlschema;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

/**
 *
 * @author Tomas Plevko <324589@mailTomáš: Práca v rámci projektu
 *
 * Vedenie týmového projektu, koordinácia členov týmu.
 *
 * Použité nástroje: Google groups - vytvorenie skupiny, snaha o koordináciu
 * prostredníctvom príspevkov Stretnutia týmu - za účelom konzultácie,
 * rozdeľovania jednotlivých úloh členom týmu. Google chat, maily - komunikácia
 * s jednotlivými členmi týmu. Tvorba dokumentácie a nápadov pomocou zdieľaného
 * google dokumentu.
 *
 * Implementačná časť:
 *
 * Implementácia tried DTDReader, DTDSerializer, DTDElement, DTDAttribute a
 * časti triedy XSDCreator.  .muni.cz>
 *
 * @version 0.1
 */
public class DTDReader {

    private static File dtd;

    /**
     * metoda, ktora sa postara o dtd subory typu public
     *
     * @param systemId
     * @param dtd
     * @throws MalformedURLException
     * @throws IOException
     */
    public static void handlePublicId(String systemId, File dtd) throws MalformedURLException, IOException {

        URL url = new URL(systemId);

        URLConnection urlC = url.openConnection();
        InputStream input = url.openStream();

        OutputStream output = new FileOutputStream(dtd);

        byte[] buf = new byte[1024];
        int len;

        while ((len = input.read(buf)) > 0) {
            output.write(buf, 0, len);
        }

        input.close();
        output.close();
    }

    /**
     * metoda, ktora sa postara o kopirovanie.
     *
     * @param systemId
     * @param dtd
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static void copyFile(String systemId, File dtd) throws FileNotFoundException, IOException {

        InputStream input = new FileInputStream(systemId);
        OutputStream output = new FileOutputStream(dtd);

        byte[] buf = new byte[1024];
        int len;

        while ((len = input.read(buf)) > 0) {
            output.write(buf, 0, len);
        }

        input.close();
        output.close();
    }

    private static File createOutputFile(String inputName, String path) {

        File output = new File(path + File.separator + inputName);

        return output;
    }
    
    /**
     * replaceXML je metoda sluziaca na premazanie vstupneho XML suboru a jeho nahradenie
     * upravenym XML suborom so zmenenou hlavickou a odstranenou DTD deklaraciou
     * 
     * @param doc
     * @param xmlFile
     * @throws TransformerException
     * @throws IOException 
     */

    public static void replaceXML(Document doc, File xmlFile) throws TransformerException, IOException {

        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer xformer = factory.newTransformer();
        DocumentType doctype = doc.getDoctype();

        xformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StreamResult output = new StreamResult(new StringWriter());
        DOMSource source = new DOMSource(doc);

        xformer.transform(source, output);
        String xmlString = output.getWriter().toString();


        Writer writer = new BufferedWriter(new FileWriter(xmlFile));

        writer.write(xmlString);

        writer.close();
    }
    
    /**
     * metoda urcena na upravenie vstupneho XML suboru - aby obsahoval referenciu 
     * na schemu validujucu dane XML
     * 
     * @param doc
     * @param schemaName
     * @return 
     */

    private static Document changeRootNode(Document doc, String schemaName) {

        Element rootNode = (Element) doc.getDocumentElement();

        rootNode.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
        rootNode.setAttribute("xsi:schemaLocation", "http://www.w3.org/namespace/ " + schemaName);
        rootNode.setAttribute("xmlns", "http://www.w3.org/namespace/");
        return doc;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws SAXException, ParserConfigurationException, FileNotFoundException, TransformerConfigurationException, TransformerException {

        //createTempFile - vytvorenie temp suboru dtd_temp.dtd - ktory obsahuje analyzovany dtd subor.

        try {

            dtd = File.createTempFile("DTD_temp.dtd", ".tmp");
            File XMLfile = new File(args[0]);

            String path = XMLfile.getAbsolutePath().
                    substring(0, XMLfile.getAbsolutePath().lastIndexOf(File.separator));

            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dbFactory.newDocumentBuilder();
            Document doc = builder.parse(XMLfile);

            DocumentType docType = doc.getDoctype();
            String publicId = docType.getPublicId();
            String systemId = docType.getSystemId();
            String internalSubset = docType.getInternalSubset();

            if (publicId != null && systemId != null) {

                handlePublicId(systemId, dtd);

            } else if (systemId != null) {


                File f = new File(systemId);
                if (f.exists()) {

                    copyFile(systemId, dtd);

                } else {

                    String input = (path + File.separator + systemId);

                    copyFile(input, dtd);
                }

            }

            if (internalSubset != null) {

                FileWriter tempDTD = new FileWriter(dtd);
                BufferedWriter out = new BufferedWriter(tempDTD);
                out.write(internalSubset);
                out.close();
            }

            DTDSerializer serializer = new DTDSerializer();

            serializer.readDTD(dtd);

            File output = null;

            String fileName = XMLfile.getName().substring(0, XMLfile.getName().lastIndexOf('.')) + ".xsd";

            output = createOutputFile(fileName, path);

            serializer.parseDTD(output);

            doc = changeRootNode(doc, fileName);

            replaceXML(doc, XMLfile);

        } catch (IOException e) {
            System.err.println("wrong file " + e);
        }
    }
}
